﻿/******************************************************************************
 * Copyright (C) 671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef GAME_SERVER_WORLDSOCKETDELEGATE_H_
#define GAME_SERVER_WORLDSOCKETDELEGATE_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <NodeCpp/Macros.h>
#include <NodeCpp/ByteBuffer.h>
#include <NodeCpp/Mutex.h>
#include <NodeCpp/Net/TcpSocketDelegate.h>
#include "Shared/Auth/AuthCrypt.h"
#include "Shared/WorldPacket.h"
#include "Shared/PacketHeader.h"
using NodeCpp::ByteBuffer;
using NodeCpp::Mutex;

class AuthSession;
class WorldSession;

class WorldSocketDelegate : public NodeCpp::Net::TcpSocketDelegate
{
public:
    WorldSocketDelegate(void);
    virtual ~WorldSocketDelegate(void);

    int GetPeerID(void) { return peer().id(); }
    const std::string& GetPeerHost(void) { return peer().host(); }
    int GetPeerPort(void) { return peer().port(); }
    std::uint32_t GetSeed(void) const { return Seed_; }

    bool IsClosing(void) const { return Closing_; }
    bool TryClose(void);
    /* 发送数据包 */
    void SendPacket(WorldPacket& _Pkt);
    /* 初始化数据包加解密 */
    void InitAuthCrypt(BigNumber& _K) 
    { AuthCrypt_.SetKey(_K.AsByteArray(), 40); AuthCrypt_.Init(); }
    /* 设置验证会话 */
    void SetAuthSession(AuthSession* _Session)
    { AuthSession_ = _Session; Authed_ = false;  }
    /* 设置游戏会话，将验证会话置空，设置为已通过验证 */
    void SetWorldSession(WorldSession* _Session)
    { WorldSession_ = _Session; AuthSession_ = NULL; Authed_ = true; }

protected:
    virtual void OnOpen(void);
    virtual void OnRead(void);
    virtual void OnWrite(void);
    virtual void OnEof(void);
    virtual void OnClose(void);
    virtual void OnError(void);
    virtual void OnTimeout(int);

private:
    bool _HandleInputHeader(void);
    bool _HandleInputPayload(void);
    bool _HandlePing(WorldPacket* _Pkt);
    bool _ProcessingPacket(WorldPacket *_Packet);

    // 验证会话
    AuthSession* AuthSession_;
    // 游戏会话
    WorldSession* WorldSession_;
    // 是否正在处理数据，如果连接正常处理数据，则不能将其关闭
    bool PacketProcessing_;
    // 是否正在关闭
    bool Closing_;

    // 连接是否通过验证
    bool Authed_;

    // 服务器随机种子
    std::uint32_t Seed_;
    // 数据包加解密
    AuthCrypt AuthCrypt_;
    // 数据包发送锁，因为包头和包体分开发送，需要加锁保证发送的是正确的包
    Mutex SendLock_;

    // 包头已经接收的数据大小
    std::uint16_t ClientHeaderRecvSize_;
    // 包头
    std::uint8_t ClientHeader_[sizeof(ClientPktHeader)];
    // 包体已经接收的数据大小
    std::uint16_t ClientPacketRecvSize_;
    // 正在接收中的数据包，完成接收后会交由逻辑层处理
    WorldPacket *ClientPacket_;

    // 客户端上次PING的时间戳
    time_t LastPingTime_;
    int OverSpeedPings_;
    DISALLOW_COPY_AND_ASSIGN(WorldSocketDelegate);
};

#endif // GAME_SERVER_WORLDSOCKETDELEGATE_H_
